package com.moli.lumpSugar.websocket;

import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONUtil;

import com.moli.lumpSugar.websocket.domain.enums.WSReqTypeEnum;
import com.moli.lumpSugar.websocket.domain.vo.request.ws.WSBaseReq;
import com.moli.lumpSugar.websocket.service.WebSocketService;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.timeout.IdleStateEvent;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import com.moli.lumpSugar.websocket.util.NettyUtil;


@Slf4j
@Sharable
public class NettyWebSocketServerHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
    private WebSocketService webSocketService;

    @Override
    public void channelActive(ChannelHandlerContext ctx){
        this.webSocketService = SpringUtil.getBean(WebSocketService.class);
        webSocketService.connect(ctx);
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx){
        // 用户主动下线
        userOffLine(ctx);
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof WebSocketServerProtocolHandler.HandshakeComplete){
            log.info("握手成功");
            String token = NettyUtil.getAttribute(ctx.channel(), NettyUtil.TOKEN);
            if (StringUtils.isNotBlank(token)){
                webSocketService.authorizeReq(ctx.channel(), token);
            }
        }else if (evt instanceof IdleStateEvent){
            log.info("心跳检测");
            IdleStateEvent event = (IdleStateEvent) evt;
            if (event.state() == IdleStateEvent.READER_IDLE_STATE_EVENT.state()){
                log.info("读空闲");
                // todo 用户下线操作
                userOffLine(ctx);
            }
        }
        // 用自定义HandShakeHandler处理器，替换原来Netty本身的WebSocketServerProtocolHandler处理类，用protocols传参，实现握手认证
        // 这样有个坏处就是，后端没办法知道一开头的protocols的值，因为token就是一个不确定的，所以不推荐用这种方式
//        else if (evt instanceof WebSocketServerProtocolHandler.ServerHandshakeStateEvent) {
//            Attribute<Object> token = ctx.channel().attr(AttributeKey.valueOf("token"));
//            webSocketService.authorizeReq(ctx.channel(), token.toString());
//        }
    }

    /*
    * 用户下线操作统一处理
    * */
    private void userOffLine(ChannelHandlerContext ctx) {
        Channel channel = ctx.channel();
        webSocketService.userOffLine(channel);
        channel.close();
    }

    // 读取客户端发送的请求报文
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
        WSBaseReq wSBaseReq = JSONUtil.toBean(msg.text(), WSBaseReq.class);
        // 判断前端传入的是那种类型
        switch (WSReqTypeEnum.of(wSBaseReq.getType())) {
            case LOGIN:
                // 登录
                webSocketService.handleLoginReq(ctx.channel());
                break;
            case AUTHORIZE:
                // 认证
                webSocketService.authorizeReq(ctx.channel(), wSBaseReq.getData());
                break;
            case HEARTBEAT:
                // 心跳
                break;
            default:
                break;
        }
    }
}
